6a8889ee3c166853b5d89a6b48f12431d416e26f
[openwrt/openwrt.git] /
1 From fd9862f726aedbc2f29a29916cabed7bcf5cadb6 Mon Sep 17 00:00:00 2001
2 From: Hang Zhou <929513338@qq.com>
3 Date: Mon, 17 Nov 2025 01:08:35 +1100
4 Subject: [PATCH] spi: bcm63xx: fix premature CS deassertion on RX-only
5 transactions
6
7 On BCM6358 (and also observed on BCM6368) the controller appears to
8 only generate as many SPI clocks as bytes that have been written into
9 the TX FIFO. For RX-only transfers the driver programs the transfer
10 length in SPI_MSG_CTL but does not write anything into the FIFO, so
11 chip select is deasserted early and the RX transfer segment is never
12 fully clocked in.
13
14 A concrete failing case is a three-transfer MAC address read from
15 SPI-NOR:
16 - TX 0x03 (read command)
17 - TX 3-byte address
18 - RX 6 bytes (MAC)
19
20 In contrast, a two-transfer JEDEC-ID read (0x9f + 6-byte RX) works
21 because the driver uses prepend_len and writes dummy bytes into the
22 TX FIFO for the RX part.
23
24 Fix this by writing 0xff dummy bytes into the TX FIFO for RX-only
25 segments so that the number of bytes written to the FIFO matches the
26 total message length seen by the controller.
27
28 Fixes: b17de076062a ("spi/bcm63xx: work around inability to keep CS up")
29
30 Signed-off-by: Hang Zhou <929513338@qq.com>
31 Link: https://patch.msgid.link/tencent_7AC88FCB3076489A4A7E6C2163DF1ACF8D06@qq.com
32 Signed-off-by: Mark Brown <broonie@kernel.org>
33 ---
34 drivers/spi/spi-bcm63xx.c | 14 ++++++++++++++
35 1 file changed, 14 insertions(+)
36
37 --- a/drivers/spi/spi-bcm63xx.c
38 +++ b/drivers/spi/spi-bcm63xx.c
39 @@ -247,6 +247,20 @@ static int bcm63xx_txrx_bufs(struct spi_
40
41 if (t->rx_buf) {
42 do_rx = true;
43 +
44 + /*
45 + * In certain hardware implementations, there appears to be a
46 + * hidden accumulator that tracks the number of bytes written into
47 + * the hardware FIFO, and this accumulator overrides the length in
48 + * the SPI_MSG_CTL register.
49 + *
50 + * Therefore, for read-only transfers, we need to write some dummy
51 + * value into the FIFO to keep the accumulator tracking the correct
52 + * length.
53 + */
54 + if (!t->tx_buf)
55 + memset_io(bs->tx_io + len, 0xFF, t->len);
56 +
57 /* prepend is half-duplex write only */
58 if (t == first)
59 prepend_len = 0;